home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 4_0 / UUPC3 / (UUPC__) / DCPGPKT.C < prev    next >
Text File  |  1992-02-10  |  32KB  |  1,127 lines

  1. /*
  2.    For best results in visual layout while viewing this file, set
  3.    tab stops to every 4 columns.
  4. */
  5.  
  6. /*
  7.    dcpgpkt.c
  8.  
  9.    Revised edition of dcp
  10.  
  11.    Stuart Lynne May/87
  12.  
  13.    Copyright (c) Richard H. Lamb 1985, 1986, 1987
  14.    Changes Copyright (c) Stuart Lynne 1987
  15.  
  16.             Portions Copyright ⌐ David Platt, 1992, 1991.  All Rights Reserved
  17.             Worldwide.
  18.  
  19.    Maintenance notes:
  20.  
  21.    25Aug87 - Allow for up to 7 windows - Jal
  22.    01Nov87 - those strncpy's should really be memcpy's! - Jal
  23.    11Sep89 - Raise TimeOut to 15 - ahd
  24.    30Apr90 - Add Jordon Brown's fix for short packet retries.
  25.              Reduce retry limit to 20                             ahd
  26.    22Jul90 - Change error retry limit from per host to per
  27.              packet.                                              ahd
  28.    22Jul90 - Add error message for number of retries exceeded     ahd
  29.    08Sep90 - Drop memmove to memcpy change supplied by Jordan
  30.              Brown, MS 6.0 and Turbo C++ agree memmove insures
  31.              no overlap
  32. */
  33.  
  34. /* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
  35.  
  36. /* 7-window "g" ptotocol */
  37.  
  38. /*
  39.    Thanks goes to John Gilmore for sending me a copy of Greg Chesson's
  40.    UUCP protocol description -- Obviously invaluable.
  41.    Thanks also go to Andrew Tannenbaum for the section on Siding window
  42.    protocols with a program example in his "Computer Networks" book.
  43. */
  44.  
  45. #include <stdio.h>
  46. #include <string.h>
  47. #include <time.h>
  48.  
  49. #include "dcp.h"
  50. #include "sio.h"
  51.  
  52. #define PKTSIZE   MAXPACK
  53.  
  54. #define HDRSIZE   6
  55. #define MAXTRY 4
  56.  
  57. /* g-packet type definitions */
  58.  
  59. #define DATA   0
  60. #define CLOSE  1
  61. #define NAK    2
  62. #define SRJ    3
  63. #define ACK    4
  64. #define  INITC 5
  65. #define INITB  6
  66. #define INITA  7
  67.  
  68. #define POK    -1
  69.  
  70. #define MAXWINDOW 7
  71. #define DFLWINDOW 3
  72. #define NBUF   8  /* always SAME as MAXSEQ ? */
  73. #define MAXSEQ 8
  74.  
  75. #define between(a,b,c) ((a<=b && b<c) || (c<a && a<=b) || (b<c && c<a))
  76.  
  77. #define nextpkt(x)    ((x + 1) % MAXSEQ)
  78.  
  79. /* packet definitions */
  80.  
  81. static int rwl, swl, swu, rwu, nbuffers, irec, timeout;
  82. static int nerr;
  83. static int GOT_SYNC, GOT_HDR;
  84. static int fseq[NBUF], outlen[NBUF], inlen[NBUF], arrived[NBUF], xmitlen[NBUF];
  85. static int nwindows;
  86. static char *outbuf[NBUF];
  87. static char *inbuf[NBUF];
  88. static long ftimer[NBUF], acktmr, naktmr;
  89. static long nakholdoff;
  90. static char rescan[PKTSIZE+HDRSIZE+10];
  91. static int rescanct, rescanoffset;
  92. static int shifts;
  93. static boolean smart_packets;
  94.  
  95. static int  gmachine(long int timeout);
  96. static void gspack(int  type,int  yyy,int  xxx,int  len,int xmit,char  *data);
  97. static int  grpack(int  *yyy,
  98.                    int  *xxx,
  99.                    int  *len,
  100.                    char *data,
  101.                    const int timeout);
  102.  
  103. static unsigned int checksum(char *data, int len);
  104.  
  105. /****************** SUB SUB SUB PACKET HANDLER ************/
  106.  
  107. /*
  108.    g o p e n p k
  109. */
  110.  
  111. int gopenpk()
  112. {
  113.    int i, xxx, yyy, len, force_big;
  114.    int maxoffer;
  115.    char tmp[PKTSIZE+1];
  116.    int sync_timeout;
  117.  
  118.    pktsize = DFLPACK;   /* change it during parse & INIT */
  119.    msgtime = MSGTIME;   /* not sure I need this for "g" proto */
  120.  
  121.    /* initialize proto parameters */
  122.    swl = nerr = nbuffers = 0;
  123.    if (!sync_timeout)
  124.       sync_timeout = PacketTimeout + 1;
  125.    swl = swu = 1;
  126.    rwl = 0;
  127.    rescanct = 0;
  128.    rescanoffset = 0;
  129.    nwindows = DFLWINDOW;
  130.    smart_packets = FALSE;
  131.    force_big = FALSE;
  132.    if (strlen(proto) > 1) {
  133.     i = proto[1] - '0';
  134.     if (i > 0 && i <= MAXWINDOW) {
  135.         nwindows = i;
  136.     }
  137.     if (proto[2] == '/' || proto[2] == ':' || proto[2] == '!') {
  138.         sscanf(proto+3, "%d", &i);
  139.         xxx = 0;
  140.         yyy = 32;
  141.         while (yyy <= MAXPACK && yyy != i) {
  142.             xxx ++;
  143.             yyy *= 2;
  144.         }
  145.         if (yyy <= MAXPACK && yyy == i) {
  146.             pktsize = i;
  147.         }
  148.         if (proto[2] == ':') {
  149.             smart_packets = TRUE;
  150.         } else if (proto[2] == '!') {
  151.             smart_packets = TRUE;
  152.             force_big = TRUE;
  153.         }
  154.     }
  155.    }
  156.    maxoffer = pktsize;
  157.    rwu = nwindows - 1; /* dcp */
  158.    for (i = 0; i < NBUF; i++) {
  159.       ftimer[i] = 0;
  160.       arrived[i] = FALSE;
  161.    }
  162.    GOT_SYNC = GOT_HDR = FALSE;
  163.  
  164.    /* 3-way handshake */
  165.    timeout = 2; /* want some timeout capability here */
  166.    gspack(INITA, 0, 0, 0, 0, NULL);
  167. rsrt:
  168.    if (nerr >= MaxErr)
  169.    {
  170.       printmsg(0,
  171.          "gopenpk: Consecutive error limit of %d exceeded, %ld total errors",
  172.           MaxErr, nerr + remote_stats.errors);
  173.       return(FAILED);
  174.    }
  175.  
  176.    /* INIT sequence. */
  177.  
  178.    switch (grpack(&yyy, &xxx, &len, NULL, PacketTimeout )) {
  179.    case INITA:
  180.       printmsg(5, "**got INITA");
  181.       if (yyy < nwindows) {
  182.           nwindows = yyy;
  183.       }
  184. #ifdef NOTDEF
  185.       nwindows = yyy;
  186.       if (nwindows > MAXWINDOW)
  187.          nwindows = MAXWINDOW;
  188. #endif
  189.       rwu = nwindows - 1;
  190.       gspack(INITB, 0, 0, 0, 0, NULL);  /* data segment (packet) size */
  191.       goto rsrt;
  192.    case INITB:
  193.       printmsg(5, "**got INITB");
  194.       i = 8 * (2 << (yyy+1));
  195.       if (i < pktsize && ! force_big)
  196.          pktsize = i;
  197.       gspack(INITC, 0, 0, 0, 0, NULL);
  198.       goto rsrt;
  199.    case INITC:
  200.       printmsg(5, "**got INITC");
  201.       if (yyy < nwindows)
  202.       {
  203.          nwindows = yyy;
  204.          rwu = nwindows - 1;
  205.       }
  206.       break;
  207.    default:
  208.       nerr++;
  209.       printmsg(5, "**got SCREW UP");
  210.       gspack(INITA, 0, 0, 0, 0, NULL);
  211.       goto rsrt;
  212.    }
  213.  
  214. /*--------------------------------------------------------------------*/
  215. /*                    Allocate the needed buffers                     */
  216. /*--------------------------------------------------------------------*/
  217.  
  218.    i = 0;
  219.    while( i < NBUF)
  220.    {
  221.  
  222.       inbuf[i] = NewPtr( maxoffer );
  223.       outbuf[i] = NewPtr( maxoffer );
  224.       if (inbuf[i] == NULL || outbuf[i] == NULL) {
  225.           printmsg(0, "*** Could not allocate packet buffers!");
  226.           return(FAILED);
  227.       }
  228.  
  229.       i ++;
  230.  
  231.    } /* while */
  232.    
  233.    nerr = 0;
  234.    nakholdoff = 0;
  235.    printmsg(1, "Channel open, g/%d/%d, smart packets %sabled", nwindows, pktsize,
  236.             smart_packets ? "en" : "dis");
  237.    return(OK); /* channel open */
  238.  
  239. } /*gopenpk*/
  240.  
  241.  
  242. /*
  243.    g c l o s e p k
  244. */
  245.  
  246. int gclosepk()
  247. {
  248.    int i;
  249.    char tmp[PKTSIZE+1];
  250.  
  251.    timeout = 1;
  252.    for (i = 0; i < MAXTRY; i++) {
  253.       gspack(CLOSE, 0, 0, 0, 0, NULL);
  254.       if (gmachine(PacketTimeout) == CLOSE)
  255.          break;
  256.    }
  257.  
  258.    printmsg(0, "%ld packets transferred, %ld errors.", remote_stats.packets,
  259.          nerr + remote_stats.errors);
  260.  
  261. /*--------------------------------------------------------------------*/
  262. /*                        Release our buffers                         */
  263. /*--------------------------------------------------------------------*/
  264.  
  265.    i = 0;
  266.  
  267.    while( i < NBUF )
  268.    {
  269.       DisposPtr(inbuf[i] );
  270.       DisposPtr( outbuf[i] );
  271.       inbuf[i] = outbuf[i] = NULL;
  272.       i++;
  273.    } /* while( i < NBUF ) */
  274.  
  275.    return(0);
  276.  
  277. } /*gclosepk*/
  278.  
  279.  
  280. /*
  281.    g g e t p k t
  282.  
  283.    Gets no more than a packet's worth of data from
  284.    the "packet I/O state machine".  May have to
  285.    periodically run the packet machine to get some packets.
  286.  
  287.    on input:   don't care
  288.    on return:  data+\0 and length in len.
  289.  
  290.    ret(0)   if all's well
  291.    ret(-1) if problems (failed)
  292. */
  293.  
  294. int ggetpkt(char *data, int *len)
  295. {
  296.    int   i;
  297.    int   retry = MaxErr;
  298.    time_t start;
  299.  
  300.    irec = 1;
  301.  
  302. /*--------------------------------------------------------------------*/
  303. /*                Loop to wait for the desired packet                 */
  304. /*--------------------------------------------------------------------*/
  305.  
  306.    time( &start );
  307.    while (!arrived[rwl] && retry)
  308.    {
  309.       if (gmachine(PacketTimeout) != POK)
  310.          return(-1);
  311.  
  312.       if (!arrived[rwl] )
  313.       {
  314.          time_t now;
  315.          if (time( &now ) > (start + PacketTimeout) )
  316.          {
  317.             printmsg(5,"ggetpkt: Timeout %d waiting for inbound packet %d",
  318.                      MaxErr - --retry, remote_stats.packets + 1);
  319. /*            timeouts++; */
  320.             start = now;
  321.          } /* if (time( now ) > (start + E_PacketTimeout) ) */
  322.       } /* if (!arrived[rwl] ) */
  323.    } /* while (!arrived[rwl] && i) */
  324.  
  325.    if (!arrived[rwl])
  326.    {
  327.       printmsg(0,"ggetpkt: Remote host failed to respond after %ld seconds",
  328.                (long) PacketTimeout * MaxErr);
  329.       gclosepk();
  330.       return -1;
  331.    }
  332.  
  333. /*--------------------------------------------------------------------*/
  334. /*                           Got a packet!                            */
  335. /*--------------------------------------------------------------------*/
  336.  
  337.    i = rwl; /*<-- mod(,rwindow) for larger than 8 seq no.s */
  338.    *len = inlen[i];
  339.    memcpy(data, inbuf[i], *len);
  340.    nerr = 0; /* reset error counter */
  341.  
  342.    arrived[i] = FALSE;
  343.    rwu = nextpkt(rwu)        ;  /* bump receive window */
  344.  
  345.    remote_stats.packets++;
  346.    remote_stats.breceived += *len;
  347.  
  348.    return(0);
  349.  
  350. } /*ggetpkt*/
  351.  
  352.  
  353.  
  354.  
  355. /*
  356.    g s e n d p k t
  357.  
  358.    Put at most a packet's worth of data in the packet state
  359.    machine for transmission.
  360.    May have to run the packet machine a few times to get
  361.    an available output slot.
  362.  
  363.    on input: data=*data; len=length of data in data.
  364.  
  365.    return:
  366.     0 if all's well
  367.    -1 if problems (failed)
  368. */
  369.  
  370. int gsendpkt(char *data, int len)
  371. {
  372.    int i1;
  373.    int delta;
  374. #ifdef _DEBUG
  375.    int savedebug = debuglevel;
  376. #endif
  377.  
  378.    irec = 0;
  379.    /* WAIT FOR INPUT i.e. if weve sent SWINDOW pkts and none have been
  380.       acked, wait for acks */
  381.    while (nbuffers >= nwindows)
  382.       if (gmachine(0) != POK)    /* Spin with no timeout             */
  383.          return(-1);
  384.  
  385.    i1 = swu;   /* <--If we ever have more than 8 seq no.s, must mod() here */
  386.  
  387. /*--------------------------------------------------------------------*/
  388. /*               Place packet in table and mark unacked               */
  389. /*--------------------------------------------------------------------*/
  390.  
  391.    memcpy(outbuf[i1], data, len);
  392.  
  393. /*--------------------------------------------------------------------*/
  394. /*                       Handle short packets.                        */
  395. /*--------------------------------------------------------------------*/
  396.  
  397.    xmitlen[i1] = pktsize;
  398.    if (smart_packets)
  399.       while ( ((len * 2) < xmitlen[i1]) && (xmitlen[i1] > 32) )
  400.          xmitlen[i1] /= 2;
  401.  
  402.    delta = xmitlen[i1] - len;
  403.    if (delta > 127)
  404.    {
  405.       memmove(outbuf[i1] + 2, outbuf[i1], len);
  406.       memset(outbuf[i1]+len+2, 0, delta - 2);
  407.                               /* Pad with nulls.  Ugh.               */
  408.       outbuf[i1][0] = (unsigned char) ((delta & 0x7f) | 0x80);
  409.       outbuf[i1][1] = (unsigned char) (delta >> 7);
  410.    } /* if (delta > 127) */
  411.    else if (delta > 0 )
  412.    {
  413.       memmove(outbuf[i1] + 1, outbuf[i1], len);
  414.       outbuf[i1][0] = (unsigned char) delta;
  415.       memset(outbuf[i1]+len+1, 0, delta - 1);
  416.                               /* Pad with nulls.  Ugh.               */
  417.    } /* else if (delta > 0 )  */
  418.  
  419. /*--------------------------------------------------------------------*/
  420. /*                            Mark packet                             */
  421. /*--------------------------------------------------------------------*/
  422.  
  423.    outlen[i1] = len;
  424.    ftimer[i1] = time((long int) NULL);
  425.    swu = nextpkt(swu);  /* bump send window */
  426.    nbuffers++;
  427.  
  428.    remote_stats.packets++;
  429.    remote_stats.bsent += len;
  430.  
  431. /*--------------------------------------------------------------------*/
  432. /*                              send it                               */
  433. /*--------------------------------------------------------------------*/
  434.  
  435.    gspack(DATA, rwl, i1, outlen[i1], xmitlen[i1], outbuf[i1]);
  436.  
  437. #ifdef _DEBUG
  438.    debuglevel = savedebug;
  439. #endif
  440.  
  441.    return(0);
  442.  
  443. } /*gsendpkt*/
  444.  
  445.  
  446. int gfilepkt()
  447. {
  448.     return 0; /* begin data phase */
  449. }
  450.  
  451. int geofpkt()
  452. {
  453.     int len;
  454.     char spacket[MAXPACK];
  455.     if(gsendpkt(spacket, 0))
  456.         return('N');
  457.     return 'Y';
  458. }
  459.  
  460. int gsendresp(state)
  461. int state;
  462. {
  463.     return OK;
  464. }
  465.  
  466. /**********  Packet Machine  ********** RH Lamb 3/87 */
  467.  
  468. /*
  469.    g m a c h i n e
  470.  
  471.    Ideally we would like to fork this process off in an infinite loop and
  472.    send and receive packets through "inbuf" and "outbuf". Can't do this in
  473.    MS-DOS so we setup "getpkt" and "sendpkt" to call this routine often and
  474.    return only when the input buffer is empty thus "blocking" the packet-
  475.    machine task.
  476. */
  477.  
  478. static int gmachine(long int timeout)
  479. {
  480.    boolean done   = FALSE;    /* True = drop out of machine loop  */
  481.    boolean close  = FALSE;    /* True = terminate connection upon
  482.                                         exit                      */
  483.    char rdata[PKTSIZE+1];
  484.  
  485.    while ( !done )
  486.    {
  487.       boolean resend = FALSE;    /* True = resend data packets       */
  488.       boolean donak  = FALSE;    /* True = NAK the other system      */
  489.  
  490.       int packet, rack, rseq, rlen, i1;
  491.       time_t expired;
  492.  
  493.       printmsg(10, "* send %d < W < %d, receive %d < W < %d, error %d",
  494.          swl, swu, rwl, rwu, nerr);
  495.  
  496. /*--------------------------------------------------------------------*/
  497. /*    Waiting for ACKs for swl to swu-1.  Next pkt to send=swu        */
  498. /*    rwl=expected pkt                                                */
  499. /*--------------------------------------------------------------------*/
  500.  
  501.       printmsg(7, "Bytes transfered %ld errors %d",
  502.        (long) (remote_stats.packets * PKTSIZE) , nerr);
  503.  
  504. /*--------------------------------------------------------------------*/
  505. /*             Attempt to retrieve a packet and handle it             */
  506. /*--------------------------------------------------------------------*/
  507.  
  508.       packet = grpack(&rack, &rseq, &rlen, rdata, timeout);
  509.       switch (packet) {
  510.  
  511.          case CLOSE:
  512.             printmsg(5, "**got CLOSE");
  513.             close = done = TRUE;
  514.             break;
  515.  
  516.          case EMPTY:
  517.             printmsg(6, "**got EMPTY");
  518.             expired = time(NULL) - PacketTimeout;
  519.             for (rack = swl; between(swl, rack, swu); rack = nextpkt(rack))
  520.             {
  521.                printmsg(6, "---> seq, elapst %d %ld", rack,
  522.                     ftimer[rack] - expired);
  523.                if (ftimer[rack] && (ftimer[rack] <= expired))
  524.                {
  525.                    printmsg(5, "*** timeout %d", rack);
  526.                          /* Since "g" is "go-back-N", when we time out we
  527.                           must send the last N pkts in order.  The generalized
  528.                           sliding window scheme relaxes this reqirment. */
  529.                    nerr++;
  530.                    resend = TRUE;
  531.                    break;
  532.                } /* if */
  533.             } /* for */
  534.             done = TRUE;
  535.             break;
  536.  
  537.          case NAK:
  538.          case ACK:
  539.             if (packet == NAK)
  540.             {
  541.                nerr++;
  542.                printmsg(5, "**got NAK %d", rack);
  543.                resend = TRUE;
  544.             }
  545.             else
  546.                printmsg(5, "**got ACK %d", rack);
  547.  
  548.             while(between(swl, rack, swu))
  549.             {                             /* S<-- -->(S+W-1)%8 */
  550.                printmsg(5, "*** ACK %d", swl);
  551.                ftimer[swl] = 0;
  552.                nbuffers--;
  553.                done = TRUE;            /* Get more data for input */
  554.                swl = nextpkt(swl);
  555.             } /* while */
  556.             if (!done && (packet == ACK)) /* Find packet?         */
  557.             {
  558.                printmsg(2,"gmachine: Received ACK for bad packet %d, window is %d-%d)", rack, swl, swu);
  559.                nerr++;                 /* Count an error and proceed */
  560.             }
  561.             break;
  562.  
  563.          case DATA:
  564.             printmsg(5, "**got DATA %d %d", rack, rseq);
  565.             i1 = nextpkt(rwl);   /* (R+1)%8 <-- -->(R+W)%8 */
  566.             if (i1 == rseq) {
  567.                nakholdoff--;
  568.                arrived[i1] = TRUE;
  569.                inlen[i1] = rlen;
  570.                memcpy(inbuf[i1], rdata, rlen);
  571.                rwl = i1;
  572.                printmsg(5, "*** ACK d %d", rwl);
  573.                gspack(ACK, rwl, 0, 0, pktsize, rdata);
  574.                done = TRUE;   /* return to caller when finished */
  575.                               /* in a mtask system, unneccesary */
  576.                while(between(swl, rack, swu))
  577.                 {                             /* S<-- -->(S+W-1)%8 */
  578.                    printmsg(5, "*** implicit ACK %d", swl);
  579.                    ftimer[swl] = 0;
  580.                    nbuffers--;
  581.                    swl = nextpkt(swl);
  582.                 } /* while */
  583.             } else {
  584.                nerr++;
  585.                printmsg(5, "*** unexpect %d ne %d - %d", rseq, rwl, rwu);
  586.                donak = TRUE;
  587.             }
  588.             break;
  589.  
  590.          case ERROR:
  591.             printmsg(5, "*** got BAD CHK");
  592.             donak = TRUE;
  593.             nakholdoff = 0; /* always NAK these to prevent stalling */
  594.             break;
  595.  
  596.          default:
  597.             printmsg(5, "*** got SCREW UP");
  598.             break;
  599.  
  600.       } /* switch */
  601.  
  602. /*--------------------------------------------------------------------*/
  603. /*      If we received an NAK or timed out, resend data packets       */
  604. /*--------------------------------------------------------------------*/
  605.  
  606.       if (resend)
  607.       for (rack = swl; between(swl, rack, swu); rack = nextpkt(rack))
  608.       {                          /* resend rack->(swu-1)             */
  609.          gspack(DATA, rwl, rack, outlen[rack], pktsize, outbuf[rack]);
  610.          printmsg(5, "*** resent %d", rack);
  611.          ftimer[rack] = time((long) NULL);
  612.       } /* for */
  613.  
  614. /*--------------------------------------------------------------------*/
  615. /*  If we have an error and have not recently sent a NAK, do so now.  */
  616. /*  We then reset our counter so we receive at least a window full of */
  617. /*                 packets before sending another NAK                 */
  618. /*--------------------------------------------------------------------*/
  619.  
  620.       if ( donak )
  621.       {
  622.          nerr++;
  623.          if ( nakholdoff <= 0 )
  624.          {
  625.             printmsg(5, "*** NAK d %d", rwl);
  626.             gspack(NAK, rwl, 0, 0, pktsize, rdata);
  627.             nakholdoff = nwindows + 1;
  628.          } /* if ( nakholdoff < 1 ) */
  629.       } /* if ( donak ) */
  630.  
  631. /*--------------------------------------------------------------------*/
  632. /*    If we have an excessive number of errors, drop out of the       */
  633. /*    loop                                                            */
  634. /*--------------------------------------------------------------------*/
  635.  
  636.       if (nerr >= MaxErr)
  637.       {
  638.          printmsg(0,
  639.             "gmachine: Consecutive error limit of %d exceeded, %ld total errors",
  640.             MaxErr, nerr + remote_stats.errors);
  641.          remote_stats.errors += nerr;
  642.          nerr = 0;
  643.          done = close = TRUE;
  644.       }
  645.    } /* while */
  646.  
  647. /*--------------------------------------------------------------------*/
  648. /*    Return to caller, gracefully terminating packet machine if      */
  649. /*    requested                                                       */
  650. /*--------------------------------------------------------------------*/
  651.  
  652.    if ( close )
  653.    {
  654.       gspack(CLOSE, 0, 0, 0, pktsize, rdata);
  655.       return CLOSE;
  656.    }
  657.    else
  658.       return POK;
  659.  
  660. } /*gmachine*/
  661.  
  662.  
  663. /*************** FRAMING *****************************/
  664.  
  665. /*
  666.    g s p a c k
  667.  
  668.    Send a packet
  669.  
  670.    type=type yyy=pkrec xxx=timesent len=length<=xmit xmit=pktsize data=*data
  671.    ret(0) always
  672. */
  673.  
  674. static void gspack(int type, int yyy, int xxx, int len, int xmit, char *data)
  675. {
  676.    unsigned int check, i;
  677.    unsigned char header[HDRSIZE];
  678.  
  679. #ifdef   LINKTEST
  680.    /***** Link Testing Mods *****/
  681.    unsigned char  dpkerr[10];
  682.    /***** End Link Testing Mods *****/
  683. #endif   /* LINKTEST */
  684.  
  685. #ifdef   LINKTEST
  686.    /***** Link Testing Mods - create artificial errors *****/
  687.    printf("**n:normal,e:error,l:lost,p:partial,h:bad header,s:new seq--> ");
  688.    gets(dpkerr);
  689.    if (dpkerr[0] == 's')
  690.       sscanf(&dpkerr[1], "%d", &xxx);
  691.    /***** End Link Testing Mods *****/
  692. #endif   /* LINKTEST */
  693.  
  694.    if ( debuglevel > 4 )
  695.       printmsg(5, "send packet type %d, yyy=%d, xxx=%d, len=%d, buf = %d",
  696.                type, yyy, xxx, len, xmit);
  697.  
  698.    header[0] = '\020';
  699.    header[4] = (unsigned char) (type << 3);
  700.  
  701.    switch (type) {
  702.  
  703.       case CLOSE:
  704.          break;   /* stop protocol */
  705.  
  706.       case NAK:
  707.          header[4] += yyy;
  708.          break;   /* reject */
  709.  
  710.       case SRJ:
  711.          break;
  712.  
  713.       case ACK:
  714.          header[4] += yyy;
  715.          break;   /* ack */
  716.  
  717.       case INITA:
  718.       case INITC:
  719.          header[4] += nwindows;
  720.          break;
  721.  
  722.       case INITB:
  723.          i = 32;
  724.          while( i < pktsize )
  725.          {
  726.             header[4] ++;
  727.             i *= 2;
  728.          }
  729.          break;
  730.  
  731.       case DATA:
  732.          header[4] = (unsigned char) (0x80 + (xxx << 3) + yyy);
  733.          if (len < pktsize)   /* Short packet?                       */
  734.          {
  735.             header[4] |= 0x40;/* Count byte handled at higher level */
  736.             printmsg(7, "data=|%.*s|", len, data);
  737.          }
  738.          else
  739.             printmsg(7, "data=|%.*s|", len, data);
  740.          break;
  741.  
  742.       default:
  743.          printmsg(0,"gspack: Invalid packet type %i",type);
  744.          return;
  745.    } /* switch */
  746.  
  747. /*--------------------------------------------------------------------*/
  748. /*    Now we finish up the header.  For data packets, determine       */
  749. /*    the K number in header[1], which specifies the number of        */
  750. /*    actual data bytes transmitted as a power of 2; we also          */
  751. /*    compute a checksum on the data.                                 */
  752. /*--------------------------------------------------------------------*/
  753.  
  754.    if (type == DATA)
  755.    {
  756.       header[1] = 1;
  757.       i = 32;
  758.       while( i < xmit )
  759.       {
  760.          header[1] ++;
  761.          i *= 2;
  762.       }
  763.  
  764.       if ( i != xmit )        /* Did it come out exact power of 2?   */
  765.       {
  766.          printmsg(0,"Packet length error ... %i != %i for K = %i",
  767.                i, xmit, (int) header[1]);
  768.          return;             /* No --> Well, we blew THAT math      */
  769.       } /* if ( i != xmit ) */
  770.  
  771. /*--------------------------------------------------------------------*/
  772. /*                        Compute the checksum                        */
  773. /*--------------------------------------------------------------------*/
  774.  
  775.       check = checksum(data, xmit);
  776.       i = header[4]; /* got to do this on PC for ex-or high bits */
  777.       i &= 0xff;
  778.       check = (check ^ i) & 0xffff;
  779.       check = (0xaaaa - check) & 0xffff;
  780.    }
  781.    else {
  782.       header[1] = 9;          /* Control packet size K number (9)    */
  783.       check = (0xaaaa - header[4]) & 0xffff;
  784.                               /* Simple checksum for control         */
  785.    } /* else */
  786.  
  787.    header[2] = (unsigned char) (check & 0xff);
  788.    header[3] = (unsigned char) ((check >> 8) & 0xff);
  789.    header[5] = (unsigned char)
  790.             ((header[1] ^ header[2] ^ header[3] ^ header[4]) & 0xff) ;
  791.  
  792. #ifdef   LINKTEST
  793.    /***** More Link Testing Mods *****/
  794.    switch(dpkerr[0]) {
  795.    case 'e':
  796.       data[10] = - data[10];
  797.       break;
  798.    case 'h':
  799.       header[5] = - header[5];
  800.       break;
  801.    case 'l':
  802.       return;
  803.    case 'p':
  804.       swrite((char *) header, HDRSIZE);
  805.       if (header[1] != 9)
  806.          swrite(data, xmit - 3);
  807.       return;
  808.    default:
  809.       break;
  810.    }
  811.    /***** End Link Testing Mods *****/
  812. #endif   /* LINKTEST */
  813.  
  814.    swrite((char *) header, HDRSIZE);      /* header is 6-bytes long */
  815.    if (header[1] != 9)
  816.       swrite(data, xmit);
  817.  
  818. } /*gspack*/
  819.  
  820.  
  821.  
  822. /*
  823.    g r p a c k
  824.  
  825.    Read packet
  826.  
  827.    on return: yyy=pkrec xxx=pksent len=length<=PKTSIZE  data=*data
  828.  
  829.    ret(type)   ok
  830.    ret(EMPTY)  input buf empty, or bad header
  831.  
  832.    ret(EMPTY)  lost packet timeout
  833.    ret(ERROR)  checksum error
  834.  
  835.    NOTE (specifications for sread()):
  836.  
  837.    sread(buf, n, timeout)
  838.       while(TRUE) {
  839.          if (# of chars available >= n) (without dec internal counter)
  840.             read n chars into buf (decrement internal char counter)
  841.             break
  842.          else
  843.             if (time > timeout)
  844.                break
  845.       }
  846.       return(# of chars available)
  847.  
  848. */
  849.  
  850. static int grpack(int *yyy, int *xxx, int *len, char *data, int timeoutX)
  851. {
  852.    unsigned int type, check, checkchk, i, total;
  853.    boolean badHeader;
  854.    unsigned char c, c2;
  855.    int hdroffset, hdrbytes, scanct, scanoffset, dbytes, dgot, doffset;
  856.    unsigned char grpkt[PKTSIZE+HDRSIZE];
  857.    const int sync_timeout = PacketTimeout + 1;
  858.                               /* Time willing to wait for sync char  */
  859.    time_t start;
  860.    time_t elapsed;
  861.  
  862.    if (GOT_HDR)
  863.       goto get_data;
  864.  
  865. /*--------------------------------------------------------------------*/
  866. /*   Spin up to timeout waiting for a Control-P, our sync character   */
  867. /*--------------------------------------------------------------------*/
  868.  
  869.    start = time((time_t) NULL); /* Rememeber we started looking for
  870.                                  sync character                      */
  871.    elapsed = 0;               /* No time has passed since start      */
  872.    
  873.    if (rescanct > 0) {
  874.       printmsg(1, "grpack: rescanning %d bytes", rescanct);
  875.    }
  876.  
  877.    while (!GOT_SYNC && (elapsed < sync_timeout))
  878.    {
  879.       if (rescanct > 0) {
  880.          c = rescan[rescanoffset++];
  881.          rescanct--;
  882.       } else if (sread( (char *) &c , 1, sync_timeout) < 1)
  883.       {
  884.          nerr++;                 /* Otherwise, we never quit!        */
  885.          return EMPTY;
  886.       }
  887.       if ((c & 0x7f) == '\020')
  888.          GOT_SYNC = TRUE;
  889.       else if ((c & 0x7f) != '\0') { /* Don't kvetch about nulls - known BSD bug */
  890.          time_t   now = time((time_t) NULL);  /* Get new time          */
  891.          elapsed = now - start;  /* Compute time used since start    */
  892.          printmsg(2, "grpack: %02x not a sync", c);
  893.       } /* else */
  894.    } /* while */
  895.  
  896.    if ( !GOT_SYNC )
  897.       return EMPTY;
  898.  
  899. /*--------------------------------------------------------------------*/
  900. /*   We are in are in sync with the other host; now process the       */
  901. /*   header which should follow.                                      */
  902. /*--------------------------------------------------------------------*/
  903.    hdroffset = 1;
  904.    hdrbytes = HDRSIZE - 1;
  905.    scanct = rescanct;
  906.    scanoffset = rescanoffset;
  907.    while (rescanct > 0 && hdrbytes > 0) {
  908.       grpkt[hdroffset++] = rescan[rescanoffset++];
  909.       rescanct--;
  910.       hdrbytes--;
  911.    }
  912.    if (hdrbytes > 0 && sread( (char *) &grpkt[hdroffset], hdrbytes, PacketTimeout) < hdrbytes) {
  913.            printmsg(2, "grpack: timeout during packet header");
  914.            return(EMPTY);
  915.    }
  916.    GOT_SYNC = FALSE;
  917.    i = (unsigned)grpkt[1] ^ (unsigned)grpkt[2] ^
  918.        (unsigned)grpkt[3] ^ (unsigned)grpkt[4] ^
  919.        (unsigned)grpkt[5];
  920.  
  921.    i &= 0xff;
  922.    printmsg(10, "prpkt %02x %02x %02x %02x %02x .. %02x ",
  923.       grpkt[1], grpkt[2], grpkt[3], grpkt[4], grpkt[5], i);
  924.  
  925.  
  926.    if (i != 0) {
  927.         printmsg(0, "*** header cksum error ***");
  928.         badHeader = TRUE;
  929.    } else if (grpkt[1] != 9 /*ctl*/ && grpkt[1] > MAXPACKCODE) {  /* bad header */
  930.         printmsg(0, "*** bad header ***");
  931.         badHeader = TRUE;
  932.    } else {
  933.         badHeader = FALSE;
  934.    }
  935.    
  936.    if (badHeader) {
  937.       if (scanct > 0) {
  938.           rescanct = scanct;
  939.           rescanoffset = scanoffset;
  940.       } else {
  941.         rescanct = HDRSIZE - 1;
  942.         rescanoffset = 0;
  943.           memcpy(rescan, &grpkt[1], rescanct);
  944.       }
  945.       return(EMPTY); /* DECUS paper says not to NAK it */
  946.    }
  947.  
  948.    GOT_HDR = TRUE;
  949.    if (grpkt[1] == 9) { /* control packet */
  950.       if ( data != NULL )
  951.          *data = '\0';
  952.       *len = 0;
  953.       c = grpkt[4];
  954.       type = c >> 3;
  955.       *yyy = c & 0x07;
  956.       *xxx = 0;
  957.       check = 0;
  958.       checkchk = 0;
  959.       GOT_HDR = FALSE;
  960.    } else { /* data packet, packet size already verified */
  961. get_data:
  962.       if ( data == NULL )
  963.       {
  964.          printmsg(0,"grpack: Unexpected data packet!");
  965.          return(ERROR);
  966.       }
  967. /*--------------------------------------------------------------------*/
  968. /*             Compute the size of the data block desired             */
  969. /*--------------------------------------------------------------------*/
  970.  
  971.       total = 8 * (2 << grpkt[1]);
  972.       if (total > MAXPACK)    /* Within the defined limits?          */
  973.       {                       /* No --> Other system has bad header,
  974.                                  or the header got corrupted         */
  975.          printmsg(0,"grpack: Invalid packet size %d (%d)",
  976.             total, (int) grpkt[1]);
  977.          GOT_HDR = FALSE;
  978.          return(ERROR);
  979.       }
  980.       if (rescanct > 0) {
  981.          if (rescanct > total) {
  982.              dbytes = total;
  983.           } else {
  984.              dbytes = rescanct;
  985.           }
  986.           memcpy(grpkt+HDRSIZE, rescan+rescanoffset, (size_t) dbytes);
  987.           doffset = dbytes;
  988.           rescanoffset += dbytes;
  989.           rescanct -= dbytes;
  990.           dbytes = total - dbytes;
  991.       } else {
  992.           dbytes = total;
  993.           doffset = 0;
  994.       }
  995.       if (dbytes > 0) {
  996.            dgot = sread((char *) grpkt+HDRSIZE+doffset, dbytes, PacketTimeout);
  997.            if (dgot < dbytes) {
  998.              rescanoffset = 0;
  999.              rescanct = doffset + dgot;
  1000.              if (rescanct < 1) {
  1001.                  printmsg(1, "Timeout while reading packet, no data");
  1002.                  rescanct = 0;
  1003.              } else {
  1004.                  printmsg(1, "Timeout while reading packet, saving %d bytes", rescanct);
  1005.                  memcpy(rescan, grpkt+HDRSIZE, (size_t) rescanct);
  1006.             }
  1007.              return(EMPTY);
  1008.          }
  1009.       }
  1010.       GOT_HDR = FALSE;
  1011.       type = 0;
  1012.       c2 = grpkt[4];
  1013.       c = (unsigned char) (c2 & 0x3f);
  1014.       *xxx = c >> 3;
  1015.       *yyy = c & 0x07;
  1016.       i = grpkt[3];
  1017.       i = (i << 8) & 0xff00;
  1018.       check = grpkt[2];
  1019.       check = i | (check & 0xff);
  1020.       checkchk = checksum((char *) grpkt+HDRSIZE, total);
  1021.       i = grpkt[4] | 0x80;
  1022.       i &= 0xff;
  1023.       checkchk = 0xaaaa - (checkchk ^ i);
  1024.       checkchk &= 0xffff;
  1025.       if (checkchk != check) {
  1026.          printmsg(4, "*** packet checksum error ***");
  1027.          rescanoffset = 0;
  1028.          rescanct = total;
  1029.          memcpy(rescan, grpkt+HDRSIZE, (size_t) rescanct);
  1030.          return(ERROR);
  1031.       }
  1032. /*--------------------------------------------------------------------*/
  1033. /*    The checksum is correct, now determine the length of the        */
  1034. /*    data to return.                                                 */
  1035. /*--------------------------------------------------------------------*/
  1036.  
  1037.       *len = total;
  1038.  
  1039.       if (c2 & 0x40)
  1040.       {
  1041.          int ii;
  1042.          if ( grpkt[HDRSIZE] & 0x80 )
  1043.          {
  1044.             ii = (grpkt[HDRSIZE] & 0x7f) + ((grpkt[HDRSIZE+1] & 0xff) << 7);
  1045.             *len -= ii;
  1046.             memcpy(data, grpkt + HDRSIZE + 2, *len);
  1047.          }
  1048.          else {
  1049.             ii = (grpkt[HDRSIZE] & 0xff);
  1050.             *len -= ii;
  1051.             memcpy(data, grpkt + HDRSIZE + 1, *len);
  1052.          } /* else */
  1053.       }
  1054.       else
  1055.          memcpy(data, grpkt + HDRSIZE, *len);
  1056.       data[*len] = '\0';
  1057.    }
  1058.  
  1059.    printmsg(12, "receive packet type %d, yyy=%d, xxx=%d, len=%d",
  1060.       type, *yyy, *xxx, *len);
  1061.    printmsg(13, " checksum rec=%04x comp=%04x\ndata=|%.*s|",
  1062.       check, checkchk, total, data);
  1063.  
  1064.    return(type);
  1065.  
  1066. } /*grpack*/
  1067.  
  1068.  
  1069. /*
  1070.    c h e c k s u m
  1071. */
  1072.  
  1073. static unsigned int checksum(char *data, int len)
  1074. {
  1075.    int i, j;
  1076.    unsigned int tmp, chk1, chk2;
  1077.    chk1 = 0xffff;
  1078.    chk2 = 0;
  1079.    j = len;
  1080.    for (i = 0; i < len; i++) {
  1081.       if (chk1 & 0x8000) {
  1082.          chk1 <<= 1;
  1083.          chk1++;
  1084.       } else {
  1085.          chk1 <<= 1;
  1086.       }
  1087.       tmp = chk1;
  1088.       chk1 += (data[i] & 0xff);
  1089.       chk2 += chk1 ^ j;
  1090.       if ((chk1 & 0xffff) <= (tmp & 0xffff))
  1091.          chk1 ^= chk2;
  1092.       j--;
  1093.    }
  1094.    return(chk1 & 0xffff);
  1095.  
  1096. } /*checksum*/
  1097.  
  1098. gwrmsg(char *str, boolean nowait)
  1099. {
  1100.     char spacket[MAXPACK];
  1101.     int len;
  1102.     len = strlen(str) + 1;
  1103.     if (nowait) {
  1104.         return gsendpkt(str, len);
  1105.     }
  1106.     while (len > pktsize)  {
  1107.         strncpy((char *) spacket, str, pktsize);
  1108.         spacket[pktsize] = '\0';
  1109.         if (gsendpkt((char *) spacket, pktsize)) /* don't re-check len */
  1110.             return(1);
  1111.         str += pktsize;
  1112.         len -= pktsize;
  1113.     }
  1114.     strcpy((char *) spacket, str);
  1115.     if (gsendpkt((char *) spacket, len))
  1116.         return 1;      /* send 'S fromfile tofile user - tofile 0666' */
  1117.     return 0;
  1118. }
  1119.  
  1120. grdmsg(register char *str, int *bytes)
  1121. {
  1122.     return ggetpkt(str, bytes);
  1123. }
  1124.  
  1125.  
  1126.  
  1127.